<?php
/**
 * Created by PhpStorm.
 * User: xi
 * Date: 16/2/23
 * Time: AM9:49
 */

namespace  Api\Util;

use Org\Net\Http;
use Admin\Model\UsersModel;
use Think\Cache;

class Wechat {


    const WEIXIN_TOKEN_API = "https://api.weixin.qq.com/sns/oauth2/access_token";
    const WEIXIN_AUTH_API = "https://open.weixin.qq.com/connect/oauth2/authorize";
    const WEIXIN_USEINFO_API = "https://api.weixin.qq.com/sns/userinfo";


    public function authorize($callbackUrl,$platform,$type,$code,$scope){

        $appid = C('WX_APP_ID');
        $secret = C('WX_SECRET');
        $accountUrl = C('AUTH_URL');
        $avater_path = C('AVATAR_PATH');
        if(!$code){
            $redirectUrl =   urlencode($accountUrl."Api/ApiUser/login?callbackUrl=".$callbackUrl.'&platform='.$platform.'&type='.$type.'&code='.$code."&scope=".$scope);
            $requestUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" . $appid . "&redirect_uri=" .$redirectUrl . "&response_type=code&scope=".$scope."&state=STATE#wechat_redirect";
            header("location:" . $requestUrl);
            exit(0);
        }else{
            if($scope == 'snsapi_base'){

                $get_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$secret.'&code='.$code.'&grant_type=authorization_code';
                $res =Helper::curl_request($get_token_url);
                $json_obj = json_decode($res,true);
                $token = $json_obj['access_token'];
                $openid = $json_obj['openid'];

                $where_w = array();
                $where_w["openid"] =  $openid;
                $weiModel = new \Admin\Model\UsersWeixinModel();
                $user_w = $weiModel->getUser($where_w);

                if(!$user_w) {
                    //重新调用
                    $this->authorize($callbackUrl,$platform,$type,'','snsapi_userinfo');
                }else{
                    $userModel = new \Admin\Model\UsersModel();
                    $uid =  $user_w['uid'];
                    $where_u = array();
                    $where_u['uid'] = $uid;
                    $user = $userModel->getUser($where_u);
                    $user['openid'] = $openid;
                    return $user;
                }
            }else{

                $get_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$secret.'&code='.$code.'&grant_type=authorization_code';
                $res =Helper::curl_request($get_token_url);
                $json_obj = json_decode($res,true);
                $token = $json_obj['access_token'];
                $openid = $json_obj['openid'];

                $where_w = array();
                $where_w["openid"] =  $openid;
                $weiModel = new \Admin\Model\UsersWeixinModel();
                $userModel = new \Admin\Model\UsersModel();
                
                // check user existence
                $user_w = $weiModel->getUser($where_w);
                if (!$user_w) {
                    // sleep
                    $num = mt_rand(1,20);
                    usleep($num*100*1000);
                    // try again to double confirm
                    $user_w = $weiModel->getUser($where_w);
                }


                if (!$user_w) {
                    // now create user
                    //获取用户信息
                    $userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" . $token . "&openid=" . $openid . "&lang=zh_CN";
                    $user_result =  Helper::curl_request($userInfoUrl);
                    
                    $userObj = json_decode($user_result, true);
                    
                    
                    $d_callbackUrl= base64_decode($callbackUrl);
                    $domain = strstr($d_callbackUrl, 'fromuid=',true);
                    $total = strlen($d_callbackUrl);
                    $prefix = strlen($domain);
                    $referer_uid = 0;
                    
                    if($prefix != 0){
                        $prefix = strlen($domain)+8;
                        $referer_uid = substr($d_callbackUrl,$prefix);
                    }
                    if (strlen(trim($userObj['nickname'])) == 0) {
                        // no nickname? using default one
                        $userObj['nickname'] = '茄子粉';
                    }

                    $data = array();
                    $username = $userObj['nickname'];
                    if($userModel->check_username($username)){
                        $username .= '_' . rand(1, 999);
                    }
                    $data['user_name'] = $username;
                    $data['password'] = md5(rand(111111, 999999999));
                    //$data['avatar_file'] = $userObj['headimgurl'];
                    $data['referer_uid'] = $referer_uid;
                    $data['referer_url'] = $d_callbackUrl;
                    $data['sex'] = $userObj['sex'];
                    $data['province'] = $userObj['province'];
                    $data['city'] = $userObj['city'];
                    $data['country'] = $userObj['country'];
                    $data['reg_time'] = time();
                    $data['from_type'] = 'weixin';
                    $data['from_platform'] = $platform;
                    $uid = $userModel->data($data)->add();
                    $data_w['openid'] = $openid;
                    $data_w['uid'] = $uid;
                    $weiModel->data($data_w)->add();


                    
                    
                    $rootPath = realpath(__ROOT__).$avater_path;
                    $path = $rootPath.$userModel->get_avatar($uid,'real',1);
                    Helper::mkDirs($path);
                    
                    $avatar_url = str_replace('wx.qlogo.cn', '180.163.26.115', $userObj['headimgurl']);
                    Http::curlDownload($avatar_url,$path.$userModel->get_avatar($uid,'real',2).'.jpg');
                    $image = new \Think\Image();
                    $size = filesize($path.$userModel->get_avatar($uid,'real',2).'.jpg');
                    if($size > 0){
                        
                        $image->open($path.$userModel->get_avatar($uid,'real',2).'.jpg');
                        $image->thumb(100, 100,\Think\Image::IMAGE_THUMB_CENTER)->save($rootPath.$userModel->get_avatar($uid,'max',0).'.jpg');
                        $image->thumb(50, 50,\Think\Image::IMAGE_THUMB_CENTER)->save($rootPath.$userModel->get_avatar($uid,'mid',0).'.jpg');
                        $image->thumb(32, 32,\Think\Image::IMAGE_THUMB_CENTER)->save($rootPath.$userModel->get_avatar($uid,'min',0).'.jpg');
                        $updateData = array();
                        $avatar_file = $userModel->get_avatar($uid,'min',0).'.jpg';
                        $updateData['uid'] = $uid;
                        $updateData['avatar_file'] = $avatar_file;
                        $r = $userModel->save($updateData);
                    }
                } else {
                    $uid = $user_w['uid'];
                }

                $where_u = array();
                $where_u['uid'] = $uid;
                $user = $userModel->getUser($where_u);
                $user['openid'] = $openid;

                return $user;

            }


        }
    }

    /**
     * 定时来检测用户的用户名
     */
    public function reset_user_info($uid){
        $where_w = array();
        $where_w["uid"] =  $uid;
        $weiModel = new \Admin\Model\UsersWeixinModel();
        $user = $weiModel->getUser($where_w);
        if(!$user){
            error_log('id 为'.$uid.'的用户不存在');
            return null;
        }
        //第一步获取access_token
        $access_token = $this->get_access_token();
        //第二步，获取用户信息
        $wx_user_info = $this->get_user_info_from_weixin($uid,$access_token,$user);
        //第三步，更新用户信息
        $userObj = $this->update_user_info($uid,$wx_user_info);
        return $userObj;
    }


    public function get_access_token(){
        $access_token = S('ACCESS_TOKEN');
        $access_token_time = S('ACCESS_TOKEN_TIME');
        error_log('access_token =============>'.json_encode($access_token));
        error_log('access_token_time expire =============>'.date('Y-m-d H:i:s',$access_token_time));
        $time = time();
        error_log('current time =============>'.date('Y-m-d H:i:s',$time));
        error_log('diff time =============>'.($access_token_time-$time).'s');
        //判断token是否过期
        if($access_token_time > $time){
            if(!$access_token){
                $access_token = $this->fetch_access_token();
            }else{
                error_log('get access token from cache =============>');
            }
        }else{
            $access_token = $this->fetch_access_token();
        }
        return $access_token;
    }


    public function fetch_access_token(){
        error_log('get access token from weixin =============>');
        $appid = C('WX_APP_ID');
        $secret = C('WX_SECRET');
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$secret;
        error_log('access_token  url =====>'.$url);
        $result = Helper::curl_request($url);
        $access_token = json_decode($result,true);
        error_log('request access_token =============>'.json_encode($access_token));
        if($access_token['errcode']){
            S('ACCESS_TOKEN','');
            error_log('获取access_token失败');
            return null ;
        }

        S('ACCESS_TOKEN',$access_token,$access_token['expires_in']);
//        为了容错减掉10s
        $access_token_time = time() + C('ACCESS_TOKEN_CACHE_TIME') ;
        S('ACCESS_TOKEN_TIME',$access_token_time);
        return $access_token;
    }


    /**
     * 根据用户id来从微信服务器上获取
     * @param $access_token 微信的access_token信息
     * @param $uid 用户编号
     */
    public function get_user_info_from_weixin($uid, $access_token,$user){

        $user_info_prefix = 'user_info_';
        //直接缓存用户的信息
        $user_info = S($user_info_prefix.$uid);
        if($user_info['errcode']){
            $this->clear_user_info_cache($uid);
            $user_info = $this->request_user_info($uid, $access_token,$user,$user_info_prefix);
        }

        $user_cache_time = S($user_info_prefix.$uid.'_time');
        error_log('user id is ['.$uid.']============user_info exprire time=========='.date('Y-m-d H:i:s',$user_cache_time));
        $now = time();
        if($user_cache_time > $now){//没有到过期时间
            error_log('============user_cache_time more than now==========');
            if(!$user_info){
                $user_info = $this->request_user_info($uid, $access_token,$user,$user_info_prefix);
            }else{
                error_log('get user info from cache ');
            }
        }else{
            error_log('==========user_cache_time less than now==========');
            //已经过期了，直接从微信服务器上抓取
            $user_info = $this->request_user_info($uid, $access_token,$user,$user_info_prefix);
        }
        return $user_info;
    }

    public function request_user_info($uid, $access_token,$user,$user_info_prefix){
        error_log('access_token =============>'.json_encode($access_token));
        $user_info_url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$access_token['access_token'].'&openid='.$user['openid'].'&lang=zh_CN';
        error_log('user_info_url  url =====>'.$user_info_url);
        $user_result = Helper::curl_request($user_info_url);
        error_log('weixin_user_info  =====>'.$user_result);
        $user_info = json_decode($user_result,true);
        if($user_info['errcode']){
            //如果拉去失败说明是缓存中的token过期，重新再拉取,回调自身
            $this->clear_access_token();
            $this->clear_user_info_cache($uid);
            $access_token = $this->fetch_access_token();
            $this->request_user_info($uid, $access_token,$user,$user_info_prefix);
        }
        //缓存用户的信息１天
        S($user_info_prefix.$uid,$user_info);
        $now = time();
//        $cache_time = $now + 20;
        //缓存时间设置为2天
        $cache_time = $now + C('WX_USER_INFO_CACHE_TIME');
//        缓存用户信息的时间设置为1天
//        S($user_info_prefix.$uid.'_time',$cache_time);
        S($user_info_prefix.$uid.'_time',$cache_time);
        error_log('user_info  =====>'.json_encode($user_info));
        return $user_info;
    }

    public function clear_access_token(){
        S('ACCESS_TOKEN',null);
        S('ACCESS_TOKEN_TIME',null);
    }

    public function clear_user_info_cache($uid){
        S('user_info_'.$uid,null);
    }

    /**
     * 更新用户表中的用户昵称以及头像信息
     * @param $userModel
     * @param $uid 用户编号
     */
    public function update_user_info($uid,$wx_user_info){
        $userModel = new \Admin\Model\UsersModel();
        $where['uid'] = $uid;
        $origin_user = $userModel->getUser($where);
        $now = time();
        $last_update_time = $origin_user['update_time'];
//        $update_user_info_flag = round(($now-$last_update_time)/3600/24);
        $diff_times = C('USER_INFO_UPDATE_TIME');
        //是否更新用户信息标志
        $update_user_info_flag = ($now - $last_update_time > $diff_times) ? true : false;

        error_log('last update time is :' . date('Y-m-d H:i:s',$last_update_time));
        error_log('current time is :' . date('Y-m-d H:i:s',$now));
        error_log('update flag is :' . $update_user_info_flag);
        $update_data = array();
        //处理用户名
        $username = $wx_user_info['nickname'];
        if (!$wx_user_info['nickname']) {
            //如果原先的用户名不为空，设置昵称不变，否则设置为茄子分
            if($origin_user['user_name']){
                $wx_user_info['nickname'] = $origin_user['user_name'];
                $update_data['user_name'] = $origin_user['user_name'];
            }else{
                $username = '茄子粉_' . rand(1, 999);
                while (true){
                    if($userModel->check_username($username)){
                        $username = '茄子粉_' . rand(1, 999);
                    }else{
                        break;
                    }
                }
                $wx_user_info['nickname'] = $username;
                $update_data['user_name'] = $username;
            }

            //判断最后更新时间和当前时间比较是否大于一天
            if($update_user_info_flag){
                $update_data['update_time']  =  $now;
            }else{
                unset($wx_user_info['nickname']);
                unset($update_data['user_name']);
            }
        }

        //处理图片
        if ($wx_user_info['headimgurl']) {
            if($update_user_info_flag){ //用户的最后更新时间
                $avatar_file = $this->handle_user_avatar($uid,$wx_user_info);
                $wx_user_info['avatar_file'] = $avatar_file;
                $update_data['avatar_file'] = $avatar_file;
                $update_data['update_time']  =  $now;
            }

        }
        error_log('update data=========>'.json_encode($update_data));
        //保存用户的图片和用户名信息
        $where = 'uid = '.$uid;
        $userModel->where($where)->save($update_data);
        return $wx_user_info;
    }


    /**
     * 处理用户的头像信息
     * @param $userModel
     * @param $uid 用户编号
     */
    public function handle_user_avatar($uid,$wx_user_info){
        $userModel = new \Admin\Model\UsersModel();
        $avater_path = C('AVATAR_PATH');
        $rootPath = realpath(__ROOT__).$avater_path;
        //删除原来的头像
        $this->delete_origin_avatar($userModel,$uid,$rootPath);


        $path = $rootPath.$userModel->get_avatar($uid,'real',1);
        Helper::mkDirs($path);

        $avatar_file = $path.$userModel->get_avatar($uid,'real',2).'.jpg';
        $avatar_url = str_replace('wx.qlogo.cn', '180.163.26.115', $wx_user_info['headimgurl']);
        Http::curlDownload($avatar_url,$avatar_file);
        $image = new \Think\Image();
        $size = filesize($avatar_file);
        if($size > 0){
            $image->open($path.$userModel->get_avatar($uid,'real',2).'.jpg');
            $image->thumb(100, 100,\Think\Image::IMAGE_THUMB_CENTER)->save($rootPath.$userModel->get_avatar($uid,'max',0).'.jpg');
            $image->thumb(50, 50,\Think\Image::IMAGE_THUMB_CENTER)->save($rootPath.$userModel->get_avatar($uid,'mid',0).'.jpg');
            $image->thumb(32, 32,\Think\Image::IMAGE_THUMB_CENTER)->save($rootPath.$userModel->get_avatar($uid,'min',0).'.jpg');
            $avatar_file = $userModel->get_avatar($uid,'min',0).'.jpg';
        }
        return $avatar_file;
    }


    /**
     * 删除原来用户的图片
     * @param $userModel
     * @param $uid 用户编号
     */
    public function delete_origin_avatar($userModel,$uid,$avatar_root_path){
        $path = $userModel->get_avatar($uid,'min',1);
        $fileName = $userModel->get_avatar($uid,'real',2);
        $config = array(
            'maxSize'    =>    3145728,
            'rootPath'   =>    './uploads/avatar/',
            'savePath'   =>    $path,
            'saveName'   =>    $fileName,
            'exts'       =>    array('jpg', 'gif', 'png', 'jpeg'),
            'autoSub'    =>    true,
            'subName'    =>    '',

        );
        error_log('avatar_root_path========>'.$avatar_root_path);
        $file = $avatar_root_path.$path.$fileName.'.jpg';
        if (file_exists($file)) {
            $result = @unlink ($file);
            $max =  $avatar_root_path.$path.$userModel->get_avatar($uid,'max',2).'.jpg';
            $mid =  $avatar_root_path.$path.$userModel->get_avatar($uid,'mid',2).'.jpg';
            $min =  $avatar_root_path.$path.$userModel->get_avatar($uid,'min',2).'.jpg';
            error_log('max pic========>'.$max);
            error_log('mid pic========>'.$mid);
            error_log('min pic========>'.$mid);
            @unlink ($file);
            @unlink ($max);
            @unlink ($mid);
            @unlink ($min);
        }
    }



    public function getAccessToken($appid,$appSecret){
        $redis_key = C('REDIS_PREFIX').C('ACCESS_TOKEN').$appid;
        $redis_info = C('REDIS');
        $cache = Cache::getInstance('Redis', $redis_info);
        if(! $token = $cache->$redis_key){
            $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appSecret;
            $result = Helper::curlRequest($url);
            $access_token = json_decode($result,true);
            if($access_token['errcode']){
                S('ACCESS_TOKEN','');
                error_log('获取access_token失败');
                return null ;
            }
            $cache->set($redis_key,$access_token['access_token'],$access_token['expires_in']-60*10);
            $token = $access_token['access_token'];
        }
        return $token;
    }


    /**
     * {
     *   "subscribe": 1,
     *   "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M",
     *   "nickname": "Band",
     *   "sex": 1,
     *   "language": "zh_CN",
     *   "city": "广州",
     *   "province": "广东",
     *   "country": "中国",
     *   "headimgurl":  "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4
     *   eMsv84eavHiaiceqxibJxCfHe/0",
     *   "subscribe_time": 1382694957,
     *   "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
     *   "remark": "",
     *   "groupid": 0,
     *   "tagid_list":[128,2]
     *   }
     *
    */
    public function getWeixinUserInfo($appid,$appsecret,$openid){
        $userInfo = [];
        $token = $this->getAccessToken($appid,$appsecret);
        $user_info_url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$token.'&openid='.$openid.'&lang=zh_CN';
        error_log('user_info_url  url =====>'.$user_info_url);
        $user_result = Helper::curlRequest($user_info_url);
        error_log('weixin_user_info  =====>'.$user_result);
        $userInfo = json_decode($user_result,true);
        return $userInfo;
    }


    /**
     * 批量获取用户信息
     */
    public function batchGetUserInfo($appid,$appsecret,$openids = []){
        if(!$openids){
            return [];
        }
        $token = $this->getAccessToken($appid,$appsecret);
        $postData = [];
        foreach ($openids as $openid){
            $obj['openid'] = $openid;
            $obj['lang'] = "zh_CN";
            array_push($postData,$obj);
        }
        $query['user_list'] = $postData;
        $query = json_encode($query);
        $url = "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=".$token;
        $json = Helper::curlRequest($url,$query);
        error_log('bath get user info ===>');
        error_log($json);
        $userList = json_decode($json,true);
        if(isset($userList['errcode'])){
            return [];
        }
        $list = [];
        foreach ($userList as $user){
            $list[$user['openid']] = $user;
        }
        return $list;
    }

} 
